/*
 * ConditionalExpressionAst.cpp
 *
 *  Created on: 12 Nov 2010
 *      Author: kn308
 */

#include <MAlice/Parser/location.hh>
#include "ConditionalExpressionAst.h"
#include <MAlice/Ast/IntegerLiteralAst.h>
#include <MAlice/Ast/CastBooleanAst.h>

namespace MAlice
{
ConditionalExpressionAst::ConditionalExpressionAst(location loc, ExpressionAst* cond, Ast* body) :  ExpressionAst(loc),
	mCond(cond), mBody(body), mLast(false)
{
	MALICE_TRACE;
}

ConditionalExpressionAst::~ConditionalExpressionAst()
{
	MALICE_TRACE;
}

Value* ConditionalExpressionAst::generate()
{
	MALICE_TRACE;
	assert(mMerge && "NullPointer: setMerge() must be called before calling a ConditionalExpressionAst::generate()");

	Codegen* g       = Codegen::get();
	Builder* builder = g->getBuilder();
	Function *F      = g->getFunction();

	BasicBlock *condBB = BasicBlock::Create(g->getContext(), "if.cond", F);
	BasicBlock *thenBB = BasicBlock::Create(g->getContext(), "if.then", F);
	BasicBlock *elseBB = (mLast) ? mMerge : BasicBlock::Create(g->getContext(), "if.else", F);

	// jump to condition block
	builder->CreateBr(condBB);
	builder->SetInsertPoint(condBB);
	builder->CreateCondBr(CastBooleanAst(mCond->mLocation, mCond).generate(), thenBB, elseBB);

	// jump to then
	builder->SetInsertPoint(thenBB);
	mBody->generate();
	builder->CreateBr(mMerge);


	F->getBasicBlockList().push_back(condBB);
	F->getBasicBlockList().push_back(thenBB);
	if (!mLast)
	{
		F->getBasicBlockList().push_back(elseBB);
	}

	// jump to else/merge
	builder->SetInsertPoint(elseBB);

	return F;
}

UnConditionalExpressionAst::UnConditionalExpressionAst(location loc, Ast* stmt) :
	ConditionalExpressionAst(loc, NULL, stmt)
{
	MALICE_TRACE;
}

UnConditionalExpressionAst::~UnConditionalExpressionAst()
{
	MALICE_TRACE;
}

Value* UnConditionalExpressionAst::generate()
{
	assert(mMerge && "NullPointer");
	assert(!mCond && "Not NullPointer");

	MALICE_TRACE;

	Codegen*  g = Codegen::get();
	Builder*  builder = g->getBuilder();
	Function* F = g->getFunction();

	BasicBlock *thenBB = BasicBlock::Create(g->getContext(), "if.then");

	// jump to then straight away
	builder->CreateBr(thenBB);
	builder->SetInsertPoint(thenBB);
	mBody->generate();
	builder->CreateBr(mMerge);

	F->getBasicBlockList().push_back(thenBB);

	// jump to else/merge
	builder->SetInsertPoint(mMerge);

	return F;
}

} // namespace MAlice
